#! /usr/bin/env python
# coding=utf-8
"""
# @copyright: Copyright (c) Huawei Technologies Co., Ltd. 2012-2018. All rights reserved.
# @Author: y00447189
# @Date: 2020-10-22 16:59:16
# @LastEditTime: 2020-10-22 11:17:42
# @LastEditors: y00447189
# @Description:
# @FilePath: getpkgship.py
# @可以输入预定的版权声明、个性签名、空行等
"""

import os
import shutil
import subprocess
import enum
from autoimport.logmodule import logger
import autoimport.getdependinfo.utils as utils

CURRENT_PATH = os.path.dirname(os.path.abspath(__file__))
OUTPUT_PATH = "output"
CONFIG_PATH = "config"
TMP_FILE_PATH = "tmp"
LOG_PATH = "log"
# 日志
this_logger = logger.init('getpkgship')
logger.add_file_handler(this_logger, "get_rpm_by_pkgship", "getpkgs")


class InputData(object):
    """
    模块输入的数据
    """
    # 输入的待查询软件包列表
    input_pkg = set()
    # 可信的分支
    credible_branches = []
    # 工作分支
    working_branches = []


class OutputData(object):
    """
    模块输出的数据
    """
    # 需要新引入的包
    new_pkg = []
    # 需要从Factory分支合入Mainline的包
    factory_to_mainline_pkg = set()
    # 可以从可信分支拉到工作分支的包
    credible_to_working_pkg = []
    # 本次查询软件包列表的所有依赖包汇总
    all_requires_pkg = []
    # 可信分支中已编译成功的包
    found_credible_pkg = []
    # 工作分支中已编译成功的包
    found_working_pkg = []


class FilterStatus(enum.Enum):
    """
    筛选pkgship输出内容状态标注
    """
    NotStarted = 1
    ReadyToStart = 2
    AlreadyStarted = 3


def get_file_path(sub_dir, file_name):
    """
    根据子目录与文件拼接处文件路径
    :param sub_dir:
    :param file_name:
    :return:
    """
    if str(sub_dir) != "":
        sub_dir = os.path.join(CURRENT_PATH, sub_dir)
        file_path = os.path.join(sub_dir, file_name)
    else:
        file_path = os.path.join(CURRENT_PATH, file_name)
    return file_path


def init_workspace():
    """
    初始化工作目录
    :return:
    """
    dirs = [OUTPUT_PATH]
    for init_dir in dirs:
        # 初始化路径
        dir_path = os.path.join(CURRENT_PATH, init_dir)
        if os.path.exists(dir_path):
            shutil.rmtree(dir_path)
        print("init_workspace dir path:", dir_path)
        os.makedirs(dir_path, exist_ok=True)


def init():
    """
    初始化
    :return: 无
    """
    # 获取输入的所有包
    conf_path = get_file_path(CONFIG_PATH, 'input_package_list.txt')
    if not os.path.isfile(conf_path):
        this_logger.error(
            "Not found the inputPackageList.txt file:%s.", conf_path)
        return False
    with open(conf_path, "r") as conf_file:
        for line in conf_file:
            InputData.input_pkg.add(line.strip())
        message = "    ".join(InputData.input_pkg)
        this_logger.debug("Init package list :%s.", message)

    this_logger.info("Init all succeed.")
    return True


def get_pkgship(pkg_name):
    """
    调用pkgship selfbuild 软件包pkgName的所有依赖
    :return: 无，输出在./tmp/pkgshipoutput_package.txt文件中
    """
    if pkg_name == "":
        this_logger.error("pkg_name is null")
        return False
    # 开始计时
    this_logger.info(
        "Get %s pkgship selfbuild start, this may take a few minutes...", pkg_name)
    pkgship_cmd = "pkgship selfbuild -s 1 -t source " + pkg_name
    try:
        output = subprocess.check_output(
            pkgship_cmd, stderr=subprocess.STDOUT, shell=True)
        pkgship_output = output.decode()
        if pkgship_output.find("selfDepend result display") == -1:
            this_logger.error(
                "Get %s pkgship selfbuild failed, output is invalid", pkg_name)
            return False
        output_file_name = "pkgshipoutput_" + pkg_name + ".txt"
        output_file = get_file_path(OUTPUT_PATH, output_file_name)
        with open(output_file, 'w+') as pkgship_output_file:
            pkgship_output_file.write(pkgship_output)
        this_logger.info(
            "Get %s pkgship selfbuild succeed.", pkg_name)
        return True
    except subprocess.TimeoutExpired as time_err:
        this_logger.error(
            "Command:%s is time out.error: %s", pkgship_cmd, time_err)
        return False
    except subprocess.CalledProcessError as call_err:
        this_logger.error(
            "Command:%s is failed.error: %s", pkgship_cmd, call_err.output.decode(encoding="utf-8"))
        return False


def get_package_from_line(line):
    """
    从一行字符串中，分割，获取第一列包名
    例如：
          zziplib              0.13.69             openEuler-20.09
    :param line: 输入行字符串
    :return: 第一列包名
    """
    line_words = line.split()
    if len(line_words) == 0:
        return ""
    return line_words[0]


def pkgship_filter(ret_package_list, package):
    """
    对pkgship查询结果进行过滤，过滤出需要新加的fedora源码包
    :return: 无
    """
    if package == "":
        this_logger.error("pkg_name is null")
        return False
    pkg_file_name = "pkgshipoutput_" + package + ".txt"
    pkg_file_path = get_file_path(OUTPUT_PATH, pkg_file_name)
    if not os.path.isfile(pkg_file_path):
        this_logger.error(
            "Not found the pkgshipoutput file:%s.", pkg_file_name)
        return False
    with open(pkg_file_path, "r") as pkgship_output_file:
        start_filter_flag = FilterStatus.NotStarted
        for line in pkgship_output_file:
            # 源码包的依赖报告起始样式为：
            #    src name                                    version             database
            # 其中如果有package name，则为二进制包的报告，忽略
            if (line.find('src name') != -1) and \
                    (line.find('database') != -1) and \
                    (line.find('package name') == -1):
                # 开始过滤报告内容
                start_filter_flag = FilterStatus.ReadyToStart
                this_logger.info(
                    "Found src package report start flag.")
                continue
            # 只检索带fedora关键字的包，目前sqlite配置为fedora，关键字可以根据实际情况扩展
            if start_filter_flag != FilterStatus.NotStarted and line.find('fedora') != -1:
                start_filter_flag = FilterStatus.AlreadyStarted
                pkg_name = get_package_from_line(line)
                if pkg_name == "":
                    this_logger.warning("Find wrong package name:%s.", pkg_name)
                    continue
                ret_package_list.append(pkg_name)
                # this_logger.debug("Add require package:%s.", pkg_name)
                continue
            # 报告结尾样式为"====="，遇到结尾直接退出循环
            if start_filter_flag == FilterStatus.AlreadyStarted and line.find(
                    '================================================') != -1:
                this_logger.info(
                    "Src package filter end. total num:%d.", len(ret_package_list))
                message = "   ".join(ret_package_list)
                this_logger.debug("Filter result:%s", message)
                return True
    return False


def get_all_pkg_ship():
    """
    获取配置的待查询包列表的所有依赖关系
    :return: 无
    """
    pkgship_output_list = []
    for package in InputData.input_pkg:
        # 1.调用pkgship selfbuild并将结果保存在output文件中
        if not get_pkgship(package):
            this_logger.info(
                "Get pkgship package :%s failed.", package)
            # 如果查询失败，则只把自己加入列表
            pkgship_output_list.append(package)
            continue

        # 2.将结果中的fedora包过滤出来
        if not pkgship_filter(pkgship_output_list, package):
            this_logger.info(
                "Filter pkgship output :%s failed.", package)
            continue

    # 列表去重
    OutputData.all_requires_pkg = utils.list_unique(pkgship_output_list)


def main():
    """
    main函数
    :return: 无
    """
    # 初始化
    if not init():
        return False
    # 从pkgship查询所有的依赖关系
    get_all_pkg_ship()
    return True

# if __name__ == '__main__':
#    main()
